<template>
	<div class="antv-content">
		<div class="antv-menu">
			<h3>基础图形列表</h3>
			<ul class="menu-list">
				<li draggable="true" @mousedown="menuDrag('defaultOval', $event)">
					<i class="icon-oval"></i> <strong>椭圆形</strong>
				</li>
				<li draggable="true" @mousedown="menuDrag('defaultSquare', $event)">
					<i class="icon-square"></i><strong>矩形</strong>
				</li>
				<li draggable="true" @mousedown="menuDrag('defaultYSquare', $event)">
					<i class="icon-ysquare"></i><strong>圆角矩形</strong>
				</li>
				<li draggable="true" @mousedown="menuDrag('defaultRhombus', $event)">
					<i class="icon-rhombus"></i><strong>菱形</strong>
				</li>
				<li draggable="true" @mousedown="menuDrag('defaultRhomboid', $event)">
					<i class="icon-rhomboid"></i><strong>平行四边形</strong>
				</li>
				<li draggable="true" @mousedown="menuDrag('defaultCircle', $event)">
					<i class="icon-circle"></i><strong>圆形</strong>
				</li>
				<li draggable="true" @mousedown="menuDrag('otherImage', $event)">
					<i class="el-icon-picture"></i><strong>图片</strong>
				</li>
			</ul>
			<!-- <div class="wrapper-btn" v-if="isChange">
				<el-button type="success" @click="handlerSend">保存当前方案</el-button>
			</div> -->
		</div>
		<div class="antv-wrapper">
			<el-scrollbar style="width: 100%">
				<!-- 滚动条要包裹的内容 -->
				<div class="wrapper-tips">
					<!-- <el-switch
						v-model="isPortsShow"
						@change="changePortsShow"
					></el-switch>
					<span>链接桩常显</span> -->
					<span
						class="wrapper-tips-item"
						title="网格显示与隐藏"
						@click="
							grid.visible = !grid.visible;
							changeGrid();
						"
					>
						<i class="iconfont icon-wangge3 fs-20"></i>
						网格
					</span>
					<span
						class="wrapper-tips-item"
						title="链接桩显示与隐藏"
						@click="
							isPortsShow = !isPortsShow;
							changePortsShow(isPortsShow);
						"
					>
						<i class="iconfont icon-wangge2 fs-20"></i>
						链接桩
					</span>
					<span
						class="wrapper-tips-item"
						title="适应画布"
						@click="changeAdaptiveCanvas"
					>
						<i class="iconfont icon-zhankai fs-20"></i>
						适应画布
					</span>
					<span
						class="wrapper-tips-item"
						title="实际尺寸"
						@click="changeActualSize"
					>
						<i class="iconfont icon-realsize24 fs-20"></i>
						实际尺寸
					</span>
					<span
						class="wrapper-tips-item"
						title="是否开启小地图"
						@click="changeMinMapShow"
					>
						<i class="iconfont icon-yingyanditu fs-20"></i>
						小地图
					</span>
					<!-- <span class="wrapper-tips-item">
						<i class="iconfont icon-tuodong fs-20"></i>
						拖拽
					</span> -->
					<span
						class="wrapper-tips-item"
						title="放大"
						:class="{ disabled: zoom >= 2 }"
						@click="EnlargeRoom"
					>
						<i class="iconfont icon-zoomin24 fs-20"></i>
						放大
					</span>
					<span
						class="wrapper-tips-item"
						title="缩小"
						:class="{ disabled: zoom <= 0.5 }"
						@click="ShrinkRoom"
					>
						<i class="iconfont icon-zoomout24 fs-20"></i>
						缩小
					</span>
					<!-- <span class="wrapper-tips-item">
						<i class="iconfont icon-tupian2 fs-20"></i>
						预览
					</span> -->
					<div class="split"></div>
					<span
						class="wrapper-tips-item"
						title="向下一层"
						:class="{ disabled: !selectCell }"
						@click="toBackLevel"
					>
						<i class="iconfont icon-xiangxiayiceng fs-20"></i>
						向下一层
					</span>
					<span
						class="wrapper-tips-item"
						title="向上一层"
						:class="{ disabled: !selectCell }"
						@click="toFrontLevel"
					>
						<i class="iconfont icon-xiangshangyiceng fs-20"></i>
						向上一层
					</span>
					<span
						class="wrapper-tips-item"
						title="复制"
						:class="{ disabled: !selectCell }"
						@click="copyCells"
					>
						<i class="iconfont icon-fuzhi fs-20"></i>
						复制
					</span>
					<span
						class="wrapper-tips-item"
						title="剪切"
						:class="{ disabled: !selectCell }"
						@click="cutCells"
					>
						<i class="iconfont icon-jianqie fs-20"></i>
						剪切
					</span>
					<span
						class="wrapper-tips-item"
						title="粘贴"
						:class="{ disabled: !selectCell }"
						@click="selectCells"
					>
						<i class="iconfont icon-niantie fs-20"></i>
						粘贴
					</span>
					<span class="wrapper-tips-item" title="全选" @click="selectAllNodes">
						<i class="iconfont icon-quanxuan1 fs-20"></i>
						全选
					</span>
					<span
						class="wrapper-tips-item"
						title="是否开启框选"
						@click="handlerSelection"
					>
						<i class="iconfont icon-kuangxuan3 fs-20"></i>
						框选
					</span>
					<div class="split"></div>
					<span
						class="wrapper-tips-item"
						title="撤销"
						:class="{ disabled: !canUndo }"
						@click="handleUndo"
					>
						<i class="iconfont icon-chexiao fs-20"></i>
						撤销
					</span>
					<span
						class="wrapper-tips-item"
						title="重做"
						:class="{ disabled: !canRedo }"
						@click="handleRedo"
					>
						<i class="iconfont icon-fanhui fs-20"></i>
						重做
					</span>
					<span class="wrapper-tips-item" title="重置">
						<i class="iconfont icon-shuaxin fs-20" @click="handlerReset"></i>
						重置
					</span>
					<span
						class="wrapper-tips-item"
						title="删除"
						:class="{ disabled: !selectCell }"
						@click="handlerDel"
					>
						<i class="iconfont icon-shanchu fs-20"></i>
						删除
					</span>
					<span
						class="wrapper-tips-item"
						title="清空画布"
						@click="handlerClear"
					>
						<i class="iconfont icon-clear fs-20"></i>
						清空
					</span>
					<div class="split"></div>
					<span
						class="wrapper-tips-item"
						@click="handlerSend"
						title="保存当前方案"
					>
						<i class="iconfont icon-baocun fs-20"></i>
						保存
					</span>
					<span
						class="wrapper-tips-item"
						@click="handlerSendPng"
						title="另存为图片"
					>
						<i class="iconfont icon-lingcun fs-20"></i>
						另存为
					</span>
					<span class="wrapper-tips-item" title="画布设置" @click="editSetting">
						<i class="iconfont icon-shezhi2 fs-20"></i>
						设置
					</span>
					<span class="wrapper-tips-item" title="提示" @click="ShortcutTips">
						<i class="iconfont icon-dengpaotishi fs-20"></i>
						提示
					</span>
				</div>
			</el-scrollbar>
			<div
				class="wrapper-canvas"
				:style="{ height: height }"
				id="wrapper"
			></div>
			<div class="wrapper-minimap" id="minimap" />
		</div>
		<div v-if="editDrawer" class="edit-main">
			<div class="edit-main-title p-b-15">
				<h3>{{ editTitle }}</h3>
				<i class="el-icon-close" @click="closeEditForm"></i>
			</div>

			<div v-if="editTitle === '快捷键设置'" class="form-main">
				<div>
					<ul>
						<li>· ctrl+c：复制</li>
						<li>· ctrl+x：剪切</li>
						<li>· ctrl+v：粘贴</li>
						<li>· ctrl+z：撤销</li>
						<li>· ctrl+shift+z：重做</li>
						<li>· delete/backspace：删除</li>
						<li>· ctrl：多选</li>
						<!-- <li>· ←：左移</li>
						<li>· ↑：上移</li>
						<li>· →：右移</li>
						<li>· ↓：下移</li> -->
					</ul>
				</div>
			</div>
			<div v-if="editTitle === '画布背景设置'" class="form-main">
				<el-form
					ref="gridForm"
					:model="grid"
					label-width="90px"
					label-position="left"
				>
					<el-form-item label="是否显示网格" label-width="110px">
						<el-switch v-model="grid.visible" @change="changeGrid"></el-switch>
					</el-form-item>
					<div v-if="grid.visible">
						<el-form-item label="网格类型">
							<el-select
								v-model="grid.type"
								size="small"
								placeholder="请选择"
								@change="changeGridType"
							>
								<el-option label="点状网格" value="dot"></el-option>
								<el-option
									label="固定网点大小的点状网格"
									value="fixedDot"
								></el-option>
								<el-option label="网状网格" value="mesh"></el-option>
								<el-option label="双线网状网格" value="doubleMesh"></el-option>
							</el-select>
						</el-form-item>
						<el-form-item label="网格大小">
							<el-input-number
								v-model="grid.size"
								size="small"
								@change="changeGrid"
								:min="2"
								:max="30"
								label="网格大小"
							></el-input-number>
						</el-form-item>
						<div v-if="grid.type !== 'doubleMesh'">
							<el-form-item label="网格颜色">
								<el-color-picker
									v-model="grid.args.color"
									size="mini"
									@change="changeGrid"
								>
								</el-color-picker>
							</el-form-item>
							<el-form-item label="网格线宽度">
								<el-input-number
									v-model="grid.args.thickness"
									size="small"
									@change="changeGrid"
									:min="0"
									:max="20"
									label="网格线宽度"
								></el-input-number>
							</el-form-item>
						</div>
						<div v-if="grid.type === 'doubleMesh'">
							<el-form-item label="主网格颜色">
								<el-color-picker
									v-model="grid.args[0].color"
									size="mini"
									@change="changeGrid"
								>
								</el-color-picker>
							</el-form-item>
							<el-form-item label="主网格线宽度">
								<el-input-number
									v-model="grid.args[0].thickness"
									size="small"
									@change="changeGrid"
									:min="0"
									:max="20"
									label="主网格线宽度"
								></el-input-number>
							</el-form-item>
							<el-form-item label="次网格颜色">
								<el-color-picker
									v-model="grid.args[1].color"
									size="mini"
									@change="changeGrid"
								>
								</el-color-picker>
							</el-form-item>
							<el-form-item label="次网格线宽度">
								<el-input-number
									v-model="grid.args[1].thickness"
									size="small"
									@change="changeGrid"
									:min="0"
									:max="20"
									label="次网格线宽度"
								></el-input-number>
							</el-form-item>
							<el-form-item label="主次网格线间隔">
								<el-input-number
									v-model="grid.args[1].factor"
									size="small"
									@change="changeGrid"
									:min="0"
									:max="20"
									label="主次网格线间隔"
								></el-input-number>
							</el-form-item>
						</div>
					</div>
				</el-form>
			</div>
			<div v-if="editTitle === '编辑节点'" class="form-main">
				<el-form ref="nodeForm" :model="form" label-width="80px">
					<el-form-item label="节点文本">
						<el-input
							v-model="form.labelText"
							size="small"
							@input="changeNode('labelText', form.labelText)"
						>
						</el-input>
					</el-form-item>
					<el-form-item label="字体大小">
						<el-input
							v-model="form.fontSize"
							size="small"
							@input="changeNode('fontSize', form.fontSize)"
						></el-input>
					</el-form-item>
					<el-form-item label="字体颜色">
						<el-color-picker
							v-model="form.fontFill"
							@change="changeNode('fontFill', form.fontFill)"
						>
						</el-color-picker>
					</el-form-item>
					<el-form-item label="节点背景">
						<el-color-picker
							v-model="form.fill"
							@change="changeNode('fill', form.fill)"
						></el-color-picker>
					</el-form-item>
					<el-form-item label="边框颜色">
						<el-color-picker
							v-model="form.stroke"
							@change="changeNode('stroke', form.stroke)"
						></el-color-picker>
					</el-form-item>
					<div class="see-box">
						<h5>预览</h5>
						<div
							class="see-item"
							:style="{
								background: form.fill,
								color: form.fontFill,
								'border-color': form.stroke,
								'font-size': form.fontSize + 'px',
							}"
						>
							{{ form.labelText }}
						</div>
					</div>
				</el-form>
			</div>
			<div v-if="editTitle === '编辑图片节点'" class="form-main">
				<el-form ref="imageForm" :model="form" label-width="80px">
					<el-form-item label="节点文本">
						<el-input
							v-model="form.labelText"
							size="small"
							@input="changeImageNode('labelText', form.labelText)"
						>
						</el-input>
					</el-form-item>
					<el-form-item label="字体颜色">
						<el-color-picker
							v-model="form.labelFill"
							@change="changeImageNode('labelFill', form.labelFill)"
						>
						</el-color-picker>
					</el-form-item>
					<el-form-item label="节点背景">
						<el-color-picker
							v-model="form.fill"
							@change="changeImageNode('fill', form.fill)"
						></el-color-picker>
					</el-form-item>
					<el-form-item label="图片地址">
						<el-input
							v-model="form.xlinkHref"
							size="small"
							placeholder="图片地址"
							@input="changeImageNode('xlinkHref', form.xlinkHref)"
						></el-input>
						<el-image
							:src="form.xlinkHref"
							style="width: 80px; height: 80px; background: #f2f2f2"
							fit="fill"
						>
						</el-image>
					</el-form-item>
					<el-form-item label="图片尺寸">
						<span style="font-size: 14px; padding-right: 5px; color: #888"
							>宽</span
						>
						<el-input-number
							v-model="form.width"
							:min="0"
							label="宽"
							size="mini"
							@change="changeImageNode('width', form.width)"
						></el-input-number>
						<span style="font-size: 14px; padding-right: 5px; color: #888"
							>高</span
						>
						<el-input-number
							v-model="form.height"
							:min="0"
							label="高"
							size="mini"
							@change="changeImageNode('height', form.height)"
						></el-input-number>
					</el-form-item>
				</el-form>
			</div>
			<div v-if="editTitle === '编辑连线'" class="form-main">
				<el-form ref="edgeForm" :model="form" label-width="80px">
					<el-form-item label="标签内容">
						<el-input
							v-model="form.label"
							size="small"
							placeholder="标签文字，空则没有"
							@input="
								changeEdgeLabel(
									form.label,
									labelForm.fontColor,
									labelForm.fill,
									labelForm.stroke
								)
							"
						></el-input>
						<div v-if="form.label" class="label-style">
							<p>
								字体颜色：<el-color-picker
									v-model="labelForm.fontColor"
									size="mini"
									@change="
										changeEdgeLabel(
											form.label,
											labelForm.fontColor,
											labelForm.fill,
											labelForm.stroke
										)
									"
								>
								</el-color-picker>
							</p>
							<p>
								背景颜色：<el-color-picker
									v-model="labelForm.fill"
									size="mini"
									@change="
										changeEdgeLabel(
											form.label,
											labelForm.fontColor,
											labelForm.fill,
											labelForm.stroke
										)
									"
								>
								</el-color-picker>
							</p>
							<p>
								描边颜色：<el-color-picker
									v-model="labelForm.stroke"
									size="mini"
									@change="
										changeEdgeLabel(
											form.label,
											labelForm.fontColor,
											labelForm.fill,
											labelForm.stroke
										)
									"
								>
								</el-color-picker>
							</p>
						</div>
					</el-form-item>
					<el-form-item label="线条颜色">
						<el-color-picker
							v-model="form.stroke"
							size="small"
							@change="changeEdgeStroke"
						></el-color-picker>
					</el-form-item>
					<el-form-item label="线条样式">
						<el-select
							v-model="form.connector"
							size="small"
							placeholder="请选择"
							@change="changeEdgeConnector"
						>
							<el-option label="直角" value="normal"></el-option>
							<el-option label="圆角" value="rounded"></el-option>
							<el-option label="平滑" value="smooth"></el-option>
							<el-option label="跳线(两线交叉)" value="jumpover"></el-option>
						</el-select>
					</el-form-item>
					<el-form-item label="线条宽度">
						<el-input-number
							v-model="form.strokeWidth"
							size="small"
							@change="changeEdgeStrokeWidth"
							:min="2"
							:step="2"
							:max="6"
							label="线条宽度"
						></el-input-number>
					</el-form-item>
					<el-form-item label="双向箭头">
						<el-switch
							v-model="form.isArrows"
							@change="changeEdgeArrows"
						></el-switch>
					</el-form-item>
					<el-form-item label="流动线条">
						<el-switch
							v-model="form.isAnit"
							@change="changeEdgeAnit"
						></el-switch>
					</el-form-item>
					<el-form-item label="调整线条">
						<el-switch
							v-model="form.isTools"
							@change="changeEdgeTools"
						></el-switch>
					</el-form-item>
				</el-form>
			</div>
			<div
				class="edit-btn"
				v-if="editTitle !== '画布背景设置' && editTitle !== '快捷键设置'"
			>
				<el-button type="danger" @click="handlerDel" style="width: 100%"
					>删除此{{
						editTitle === "编辑节点" || editTitle === "编辑图片节点"
							? "节点"
							: "连线"
					}}
				</el-button>
			</div>
		</div>
	</div>
</template>
<script>
import {
	configSetting,
	configNodeShape,
	configNodePorts,
	configEdgeLabel,
	graphBindKey,
} from "@/utils/antvSetting";
// import { register, getTeleport } from "@antv/x6-vue-shape/lib";
import { Graph, Shape, Path, Edge, Platform, DataUri } from "@antv/x6";
import { Transform } from "@antv/x6-plugin-transform";
import { Selection } from "@antv/x6-plugin-selection";
import { Snapline } from "@antv/x6-plugin-snapline";
import { Keyboard } from "@antv/x6-plugin-keyboard";
import { Clipboard } from "@antv/x6-plugin-clipboard";
import { History } from "@antv/x6-plugin-history";
import { Scroller } from "@antv/x6-plugin-scroller";
import { Dnd } from "@antv/x6-plugin-dnd";
import { MiniMap } from "@antv/x6-plugin-minimap";
import { Export } from "@antv/x6-plugin-export";
export default {
	name: "AntV6X",
	/**
	 * 这个是作为子组件分别接受了两个数据一个是高度height，一个是反显图表数据tempGroupJson
	 * 作为子组件例子 <AntVXSix v-model="tempGroupJson" height="720px" />
	 *
	 */
	props: {
		height: {
			type: String,
			default: "100%",
		},
		value: {
			type: Array,
			default: () => {},
		},
	},
	data() {
		return {
			graph: null, //实例化 Graph 对象
			dnd: null, //节点拖拽函数
			isChange: false, //画布是否有变动
			isPortsShow: false, //链接桩常显
			menuItem: "", //节点的预设类型
			selectCell: "", //当前选中或点击的节点/边
			editDrawer: false, //侧边栏编辑抽屉隐藏
			editTitle: "", //编辑名称
			form: {}, //节点/边参数
			labelForm: {
				//标签内容参数
				fontColor: "#333", //字体颜色
				fill: "#FFF", //背景颜色
				stroke: "#555", //描边颜色
			},
			grid: {
				// 网格参数设置
				size: 20, // 网格大小 10px
				visible: true, // 渲染网格背景
				type: "mesh",
				args: {
					color: "#ccc", // 主网格线颜色
					thickness: 1, //  主网格线宽度/网格点大小
				},
			},
			minMapShow: false, // 小地图的显示与隐藏
			canRedo: false, // 是否可以重做
			canUndo: false, // 是否可以撤销
			zoom: 1, //画布缩放值
		};
	},
	created() {},
	watch: {
		value: {
			handler: function () {
				this.isValueChange();
			},
			deep: true,
			immediate: true,
		},
	},
	mounted() {
		this.initGraph();
	},
	beforeDestroy() {
		this.graph.dispose();
	},
	methods: {
		isValueChange() {
			if (this.graph) {
				this.dnd = null; //节点拖拽函数
				this.isChange = false; //画布是否有变动
				this.isPortsShow = false; //链接桩常显
				this.menuItem = ""; //节点的预设类型
				this.selectCell = ""; //当前选中或点击的节点/边
				this.editDrawer = false; ///侧边栏编辑抽屉隐藏
				this.minMapShow = false; // 小地图的显示与隐藏
				this.canRedo = false; // 是否可以重做
				this.canUndo = false; // 是否可以撤销
				this.zoom = 1; //画布缩放值
				this.graph.dispose();
				this.initGraph();
			}
		},
		// 链接桩的显示与隐藏，主要是照顾菱形
		changePortsShow(val, node) {
			const container = document.getElementById("wrapper");
			let ports = [];
			if (node) {
				ports = container.querySelectorAll(
					`g[data-cell-id="${node.id}"] .x6-port-body`
				);
			} else {
				ports = container.querySelectorAll(".x6-port-body");
			}
			for (let i = 0, len = ports.length; i < len; i = i + 1) {
				ports[i].style.visibility = val ? "visible" : "hidden";
			}
		},
		// 适应画布
		changeAdaptiveCanvas() {
			// 缩放画布内容，使画布内容充满视口
			this.graph.zoomToFit({ padding: 10, maxScale: 2 });
			this.graph.centerContent(); // 将画布中元素居中展示

			this.zoom = this.graph.zoom();
		},
		// 实际尺寸
		changeActualSize() {
			this.graph.zoomTo(1);
			this.zoom = this.graph.zoom();
		},
		// 小地图的显示与隐藏
		changeMinMapShow() {
			// minMapShow -- true（显示）-- false（隐藏）
			this.minMapShow = !this.minMapShow;
			if (this.minMapShow) {
				// 如果小地图的实例显示，重新注册
				this.graph.use(
					new MiniMap({
						container: document.getElementById("minimap"),
						width: 200,
						height: 160,
						scalable: false,
						minScale: 0.1,
						maxScale: 2,
						padding: 10,
					})
				);
			} else {
				// 移除创建
				this.graph.disposePlugins("minimap");
			}
		},
		// 放大
		EnlargeRoom() {
			const zoom = this.graph.zoom().toFixed(1); //获取画布缩放比例
			if (zoom < 2) {
				this.graph.zoom(0.1);
				this.zoom = this.graph.zoom().toFixed(1);
			}
		},
		// 缩小
		ShrinkRoom() {
			const zoom = this.graph.zoom().toFixed(1); //获取画布缩放比例
			if (zoom > 0.5) {
				this.graph.zoom(-0.1);
				this.zoom = this.graph.zoom().toFixed(1);
			}
		},
		// 向下一层
		toBackLevel() {
			const cells = this.graph.getSelectedCells(); //获取选中的节点/边
			if (cells.length) {
				this.selectCell.toBack();
			}
		},
		// 向上一层
		toFrontLevel() {
			const cells = this.graph.getSelectedCells(); //获取选中的节点/边
			if (cells.length) {
				this.selectCell.toFront();
			}
		},
		// 复制
		copyCells() {
			const cells = this.graph.getSelectedCells(); //获取选中的节点/边
			if (cells.length) {
				this.graph.copy(cells); //复制节点/边
			} else {
				this.$message({ type: "info", message: "请先选中节点再复制" });
			}
		},
		// 剪切
		cutCells() {
			const cells = this.graph.getSelectedCells(); //获取选中的节点/边
			if (cells.length) {
				this.graph.cut(cells); //剪切节点/边
			} else {
				this.$message({ type: "info", message: "请先选中节点再剪切" });
			}
		},
		// 粘贴
		selectCells() {
			if (!this.graph.isClipboardEmpty()) {
				//返回剪切板是否为空
				const cells = this.graph.paste({ offset: 30, useLocalStorage: true }); //粘贴，返回粘贴到画布的节点/边。
				this.graph.cleanSelection(); //清空选区。
				this.graph.select(cells); //选中指定的节点/边
			} else {
				this.$message({ type: "info", message: "剪切板为空，不可粘贴!" });
			}
		},
		// 全选
		selectAllNodes() {
			const nodes = this.graph.getNodes(); //返回画布中所有节点
			if (nodes) {
				this.graph.select(nodes); //选中指定的节点/边
			}
		},
		// 撤销
		handleUndo() {
			if (this.graph.canUndo()) {
				//是否可以撤销
				this.graph.undo(); //撤销
			}
		},

		// 重做
		handleRedo() {
			if (this.graph.canRedo()) {
				//是否可以重做
				this.graph.redo(); //重做
			}
		},
		// 重置
		handlerReset() {
			this.isValueChange();
		},
		// 清空
		handlerClear() {
			this.graph.clearCells(); //清空画布
		},
		// 框选
		handlerSelection() {
			if (this.graph.isRubberbandEnabled()) {
				this.graph.disableRubberband();
				this.graph.enablePanning();
			} else {
				this.graph.enableRubberband();
				this.graph.disablePanning();
			}
		},
		// 注册插件
		handleUsePlugin() {
			this.graph
				.use(
					new Transform({
						resizing: true,
						rotating: true,
					})
				)
				.use(
					//点选/框选,开启后可以通过点击或者套索框选节点
					new Selection({
						enabled: true, //启用
						rubberband: false, //是否启用框选
						showNodeSelectionBox: true, //是否显示节点的选择框
					})
				)
				// .use(
				// 	new Scroller({
				// 		enabled: true,
				// 		autoResize: true,
				// 		pannable: true, //是否启用画布平移能力// modifiers: ["alt", "ctrl", "meta"], //设置修饰键后需要点击鼠标并按下修饰键才能触发画布拖拽
				// 		eventTypes: ["leftMouseDown"],
				// 	})
				// )
				.use(new Snapline())
				.use(new Keyboard())
				.use(new Clipboard())
				.use(new History())
				.use(new Export());
		},

		// 初始化渲染画布
		initGraph() {
			// 事件交互对象：cell 节点/边 -- node 节点	-- edge 边 -- blank 画布空白区域
			// 创建 Graph 对象，并引入基本设置
			const graph = new Graph({
				container: document.getElementById("wrapper"),
				...configSetting(Shape),
			});
			this.graph = graph;
			// 画布键盘事件绑定
			this.handleUsePlugin();
			graphBindKey(this.graph);
			// 画布事件 - 鼠标进入节点
			this.graph.on("node:mouseenter", ({ node }) => {
				this.changePortsShow(true, node);
			});
			//鼠标离开节点
			this.graph.on("node:mouseleave", ({ node }) => {
				if (this.isPortsShow) return; //如果链接桩常显状态开启，直接return
				this.changePortsShow(false, node);
			});
			// 点击空白网格
			this.graph.on("blank:click", () => {
				// this.editGrid();
			});
			// 点击编辑节点/边
			this.graph.on("cell:click", ({ cell }) => {
				this.editForm(cell);
				if (this.isPortsShow) return; //如果链接桩常显状态开启，直接return
				this.changePortsShow(false, cell);
			});

			// 历史改变
			this.graph.on("history:change", () => {
				this.canRedo = this.graph.canRedo();
				this.canUndo = this.graph.canUndo();
			});
			// 画布有变化
			graph.on("cell:changed", () => {
				this.isChangeValue();
			});
			// 删除
			this.graph.bindKey(["delete", "backspace"], () => {
				this.handlerDel();
			});
			// 赋值
			// 返现方法
			if (this.value && this.value.length) {
				const resArr = this.value;
				// 导出的时候删除了链接桩设置加回来
				const portsGroups = configNodePorts().groups;
				if (resArr.length) {
					const jsonTemp = resArr.map((item) => {
						if (item.ports) item.ports.groups = portsGroups;
						return item;
					});
					graph.fromJSON(jsonTemp);
				}
			}
			// 指定画布拖拽区
			this.dnd = new Dnd({
				target: this.graph,
				scaled: false,
				dndContainer: document.querySelector(".antv-menu"),
				// 确保拖拽节点时和拖拽完成后节点id一致
				getDragNode: (node) => node.clone({ keepId: true }),
				getDropNode: (node) => {
					// 拖拽结束后
					let data = node.getData();
					// this.menuItem = {
					// 	...data,
					// 	id: node.id,
					// 	isCreate: true,
					// 	showDrawer: true,
					// };
					// console.log("this.menuItem :>> ", this.menuItem);
					return node.clone({ keepId: true });
				},
			});

			this.graph.zoomTo(1);
			this.changeGrid();

			this.graph.enablePanning();
		},
		// 网格参数设置
		changeGridType(e) {
			this.grid.type = e;
			if (this.grid.type === "doubleMesh") {
				this.grid.args = [
					{
						color: "#ccc", // 主网格线颜色
						thickness: 1, //  主网格线宽度/网格点大小
					},
					{
						color: "#999", // 次网格线颜色
						thickness: 1, // 次网格线宽度
						factor: 4, // 主次网格线间隔
					},
				];
			} else {
				this.grid.args = {
					color: "#ccc", // 主网格线颜色
					thickness: 1, //  主网格线宽度/网格点大小
				};
			}
			this.changeGrid();
		},
		// 网格绘制
		changeGrid() {
			this.graph.drawGrid({
				...this.grid,
			});
		},
		//  点击编辑空白网格
		editGrid() {
			this.editTitle = "画布背景设置";
			//侧边栏编辑抽屉显现
			return (this.editDrawer = true);
		},
		// 画布是否有变动
		isChangeValue() {
			if (!this.isChange) {
				this.isChange = true;
				this.$emit("cellChanged", true);
			}
		},
		// 菜单拖拽
		menuDrag(type, event) {
			this.menuItem = configNodeShape(type); //生成节点的预设类型

			const nodeItem = {
				...this.menuItem,
				// 获取节点拖拽完成后的位置，鼠标落地点为图形中心点（需要减去自身宽/高的一半,否则鼠标落地点为以图形左上角）
				// x: event.offsetX - this.menuItem.width / 2,
				// y: event.offsetY - this.menuItem.height / 2,
				ports: configNodePorts(), //初始化节点连接装设置
			};
			// 创建节点
			const node = this.graph.createNode(nodeItem);

			this.dnd.start(node, event);
			// 判断画布变动
			this.isChangeValue();
		},
		//松开鼠标完成拖拽后触发
		drop(event) {
			const nodeItem = {
				...this.menuItem,
				// 获取节点拖拽完成后的位置，鼠标落地点为图形中心点（需要减去自身宽/高的一半,否则鼠标落地点为以图形左上角）
				x: event.offsetX - this.menuItem.width / 2,
				y: event.offsetY - this.menuItem.height / 2,
				ports: configNodePorts(), //初始化节点连接装设置
			};
			// 创建节点
			this.graph.addNode(nodeItem);
			// 判断画布变动
			this.isChangeValue();
		},
		//点击编辑节点/边
		editForm(cell) {
			console.log("obje点击编辑节点/边ct");
			if (this.selectCell) this.selectCell.removeTools(); //删除所有工具
			this.selectCell = cell; //当前选中或点击的节点/边
			// 编辑node节点
			if (
				cell.isNode() &&
				cell.data.type &&
				cell.data.type.includes("default")
			) {
				this.editTitle = "编辑节点"; //节点/边参数编辑名称
				const body =
					cell.attrs.body ||
					cell.attrs.rect ||
					cell.attrs.polygon ||
					cell.attrs.circle;
				//节点参数
				this.form = {
					labelText: cell.attrs.label.text || "", //节点文本
					fontSize: cell.attrs.label.fontSize || 14, //字体大小
					fontFill: cell.attrs.label.fill || "", //字体颜色
					fill: body.fill || "", //节点背景
					stroke: body.stroke || "", //边框颜色
				};
				//侧边栏编辑抽屉显现
				return (this.editDrawer = true);
			}
			// 编辑图片节点
			if (cell.isNode() && cell.data.type && cell.data.type === "otherImage") {
				this.editTitle = "编辑图片节点";
				const attrs = cell.attrs || {
					body: { fill: "" },
					label: { text: "", fill: "" },
					image: { xlinkHref: "", height: 80, width: 80 },
				};
				//节点参数
				this.form = {
					labelText: attrs.label.text, //节点文本
					labelFill: attrs.label.fill, //字体颜色
					fill: attrs.body.fill, //节点背景
					height: (attrs.image && attrs.image.height) || 80, //图片尺寸
					width: (attrs.image && attrs.image.width) || 80, //图片尺寸
					//图片地址
					xlinkHref:
						(attrs.xlinkHref && attrs.image.xlinkHref) ||
						"https://copyright.bdstatic.com/vcg/creative/cc9c744cf9f7c864889c563cbdeddce6.jpg@h_1280",
				};
				//侧边栏编辑抽屉显现
				return (this.editDrawer = true);
			}
			// 编辑线
			if (!cell.isNode() && cell.shape === "edge") {
				this.editTitle = "编辑连线";
				//边参数
				this.form = {
					label:
						cell.labels && cell.labels[0]
							? cell.labels[0].attrs.labelText.text
							: "",
					stroke: cell.attrs.line.stroke || "",
					connector: "normal",
					strokeWidth: cell.attrs.line.strokeWidth || "",
					isArrows: cell.attrs.line.sourceMarker ? true : false, //sourceMarker - 起始箭头
					isAnit: cell.attrs.line.strokeDasharray ? true : false, //流动线条
					isTools: false, //调整线条
				};
				// 看是否有label
				const edgeCellLabel =
					(cell.labels && cell.labels[0] && cell.labels[0].attrs) || false;
				if (this.form.label && edgeCellLabel) {
					//标签内容参数
					this.labelForm = {
						fontColor: edgeCellLabel.labelText.fill || "#333", //字体颜色
						fill: edgeCellLabel.labelBody.fill || "#fff", //背景颜色
						stroke: edgeCellLabel.labelBody.stroke || "#555", //描边颜色
					};
				} else {
					this.labelForm = { fontColor: "#333", fill: "#FFF", stroke: "#333" };
				}
				//侧边栏编辑抽屉显现
				return (this.editDrawer = true);
			}
		},
		// 隐藏侧边栏编辑抽屉
		closeEditForm() {
			this.editDrawer = false;
			if (this.selectCell) this.selectCell.removeTools(); //删除所有工具
		},
		// 修改一般节点
		changeNode(type, value) {
			switch (type) {
				case "labelText":
					this.selectCell.attr("label/text", value);
					break;
				case "fontSize":
					this.selectCell.attr("label/fontSize", value);
					break;
				case "fontFill":
					this.selectCell.attr("label/fill", value);
					break;
				case "fill":
					this.selectCell.attr("body/fill", value);
					break;
				case "stroke":
					this.selectCell.attr("body/stroke", value);
					break;
			}
		},
		// 修改图片节点
		changeImageNode(type, value) {
			switch (type) {
				case "labelText":
					this.selectCell.attr("label/text", value);
					break;
				case "labelFill":
					this.selectCell.attr("label/fill", value);
					break;
				case "fill":
					this.selectCell.attr("body/fill", value);
					break;
				case "xlinkHref":
					this.selectCell.attr("image/xlinkHref", value);
					break;
				case "height":
					this.selectCell.attr("image/height", value);
					break;
				case "width":
					this.selectCell.attr("image/width", value);
					break;
			}
		},
		// 修改边label属性
		changeEdgeLabel(label, fontColor, fill, stroke) {
			this.selectCell.setLabels([
				configEdgeLabel(label, fontColor, fill, stroke),
			]);
			if (!label)
				this.labelForm = { fontColor: "#333", fill: "#FFF", stroke: "#555" };
		},
		// 修改边的颜色
		changeEdgeStroke(val) {
			this.selectCell.attr("line/stroke", val);
		},
		// 边的样式
		changeEdgeConnector(val) {
			switch (val) {
				case "normal":
					this.selectCell.setConnector(val);
					break;
				case "smooth":
					this.selectCell.setConnector(val);
					break;
				case "rounded":
					this.selectCell.setConnector(val, { radius: 20 });
					break;
				case "jumpover":
					this.selectCell.setConnector(val, { radius: 20 });
					break;
			}
		},
		// 边的宽度
		changeEdgeStrokeWidth(val) {
			if (this.form.isArrows) {
				this.selectCell.attr({
					line: {
						strokeWidth: val,
						sourceMarker: {
							width: 12 * (val / 2) || 12,
							height: 8 * (val / 2) || 8,
						},
						targetMarker: {
							width: 12 * (val / 2) || 12,
							height: 8 * (val / 2) || 8,
						},
					},
				});
			} else {
				this.selectCell.attr({
					line: {
						strokeWidth: val,
						targetMarker: {
							width: 12 * (val / 2) || 12,
							height: 8 * (val / 2) || 8,
						},
					},
				});
			}
		},
		// 边的箭头
		changeEdgeArrows(val) {
			if (val) {
				this.selectCell.attr({
					line: {
						sourceMarker: {
							name: "block",
							width: 12 * (this.form.strokeWidth / 2) || 12,
							height: 8 * (this.form.strokeWidth / 2) || 8,
						},
						targetMarker: {
							name: "block",
							width: 12 * (this.form.strokeWidth / 2) || 12,
							height: 8 * (this.form.strokeWidth / 2) || 8,
						},
					},
				});
			} else {
				this.selectCell.attr({
					line: {
						sourceMarker: "",
						targetMarker: {
							name: "block",
							size: 10 * (this.form.strokeWidth / 2) || 10,
						},
					},
				});
			}
		},
		// 边的添加蚂蚁线
		changeEdgeAnit(val) {
			if (val) {
				this.selectCell.attr({
					line: {
						strokeDasharray: 5,
						style: {
							animation: "ant-line 30s infinite linear",
						},
					},
				});
			} else {
				this.selectCell.attr({
					line: {
						strokeDasharray: 0,
						style: {
							animation: "",
						},
					},
				});
			}
		},
		// 给线添加调节工具
		changeEdgeTools(val) {
			if (val) this.selectCell.addTools(["vertices", "segments"]);
			else this.selectCell.removeTools();
		},
		// 删除节点
		handlerDel() {
			this.$confirm(
				`此操作将永久删除此${
					this.editTitle === "编辑节点" || this.editTitle === "编辑图片节点"
						? "节点"
						: "连线"
				}, 是否继续?`,
				"提示",
				{
					confirmButtonText: "确定",
					cancelButtonText: "取消",
					type: "warning",
				}
			)
				.then(() => {
					const cells = this.graph.getSelectedCells(); //获取选中的节点/边
					if (cells.length) {
						this.graph.removeCells(cells);
						this.form = {};
						this.editDrawer = false;
						this.selectCell = "";
						this.$message({ type: "success", message: "删除成功!" });
					}
				})
				.catch(() => {});
		},
		// 导出
		handlerSend() {
			// 我在这里删除了链接桩的设置，和工具（为了减少数据），反显的时候要把删除的链接桩加回来
			const { cells: jsonArr } = this.graph.toJSON();
			const tempGroupJson = jsonArr.map((item) => {
				if (item.ports && item.ports.groups) delete item.ports.groups;
				if (item.tools) delete item.tools;
				return item;
			});
			if (this.selectCell) {
				this.selectCell.removeTools();
				this.selectCell = "";
			}
			this.$emit("finish", JSON.stringify(tempGroupJson));
		},
		//另存为图片
		handlerSendPng() {
			this.graph.toPNG(
				(dataUri) => {
					// 下载
					DataUri.downloadDataUri(dataUri, "chart.png");
				},
				{
					copyStyles: false,
					padding: {
						top: 20,
						right: 30,
						bottom: 40,
						left: 50,
					},
				}
			);
		},
		editSetting() {
			this.editGrid();
		},
		ShortcutTips() {
			this.editTitle = "快捷键设置";
			//侧边栏编辑抽屉显现
			return (this.editDrawer = true);
		},
	},
};
</script>
<style lang="scss">
@keyframes ant-line {
	to {
		stroke-dashoffset: -1000;
	}
}
</style>
<style lang="scss" scoped>
.antv-content {
	height: 100%;
	width: 100%;
	position: relative;
	background: #fff;
	display: flex;
	flex-direction: row;
	align-items: stretch;
	overflow: hidden;

	.antv-menu {
		width: 200px !important;
		border-right: 1px solid #d5d5d5;
		padding: 10px;
		overflow: hidden;
		box-shadow: 0 2px 8px #f0f1f2;

		h3 {
			padding: 10px;
		}

		li {
			padding: 10px;
			border-radius: 8px;
			border: 1px solid #555;
			background: #fff;
			margin: 5px 10px;
			font-size: 12px;
			display: flex;
			align-items: center;
			cursor: pointer;
			transition: all 0.5s ease;

			&:hover {
				box-shadow: 0 0 5px rgba($color: #000000, $alpha: 0.3);
			}

			i {
				font-size: 18px;
				margin-right: 10px;
			}

			strong {
				flex: 1;
			}
		}
	}

	.antv-wrapper {
		display: flex;
		flex: 1;
		flex-direction: column;
		overflow: hidden;

		.wrapper-tips {
			height: 56px;
			box-shadow: 0 2px 8px #f0f1f2;
			justify-content: flex-start;
			padding: 0 16px;
			display: flex;
			align-items: center;
			user-select: none;
			font-size: 14px;
			flex-direction: row;
			min-width: 1300px;
			.split {
				width: 10px;
				height: 100%;
				border-right: 1px solid #eee;
				margin-right: 10px;
			}
			.wrapper-tips-item {
				// padding-left: 10px;
				font-size: 12px;
				width: 60px;
				height: 48px;
				outline: none;
				cursor: pointer;
				color: #777;
				display: flex;
				justify-content: center;
				align-items: center;
				flex-direction: column;
				gap: 3px;
			}
			.disabled {
				color: rgba(0, 0, 0, 0.25);
				cursor: not-allowed;
			}
		}
		.wrapper-canvas {
			position: relative;
			flex: 1;
			overflow: hidden;
			user-select: none;
		}
		.wrapper-minimap {
			position: absolute;
			bottom: 20px;
			right: 20px;
		}
	}
}

i.icon-oval {
	display: inline-block;
	width: 16px;
	height: 10px;
	border-radius: 10px;
	border: 2px solid #555;
}

i.icon-square {
	display: inline-block;
	width: 16px;
	height: 10px;
	border: 2px solid #555;
}

i.icon-ysquare {
	display: inline-block;
	width: 16px;
	height: 10px;
	border-radius: 4px;
	border: 2px solid #555;
}

i.icon-rhombus {
	display: inline-block;
	width: 10px;
	height: 10px;
	border: 2px solid #555;
	transform: rotate(45deg);
}

i.icon-rhomboid {
	display: inline-block;
	width: 10px;
	height: 10px;
	border: 2px solid #555;
	transform: skew(-30deg);
}

i.icon-circle {
	display: inline-block;
	width: 16px;
	height: 16px;
	border-radius: 16px;
	border: 2px solid #555;
}

.edit-main {
	position: absolute;
	right: 0;
	top: 0;
	height: 100%;
	width: 280px;
	border-left: 1px solid #f2f2f2;
	box-shadow: 0 -10px 10px rgba($color: #000000, $alpha: 0.3);
	padding: 20px;
	background: #fff;
	box-sizing: border-box;

	.edit-main-title {
		display: flex;
		justify-content: space-between;
		align-items: center;
		border-bottom: 1px solid #e8eaec;
		h3 {
			flex: 1;
		}

		i {
			cursor: pointer;
			font-size: 20px;
			opacity: 0.7;

			&:hover {
				opacity: 1;
			}
		}
	}

	.form-main {
		padding: 20px 0;

		.label-style {
			background: #f2f2f2;
			padding: 0 10px;

			p {
				display: flex;
				align-items: center;
				font-size: 12px;
			}
		}
	}

	.edit-btn {
	}

	.see-box {
		padding: 20px;
		background: #f2f2f2;

		h5 {
			padding-bottom: 10px;
		}

		.see-item {
			padding: 10px 30px;
			border: 2px solid #333;
			text-align: center;
		}
	}
}

.wrapper-btn {
	text-align: center;
	padding: 20px;

	button {
		width: 100%;
	}
}

/* 连线中的label 样式*/
.jtk-overlay.flowLabel:not(.aLabel) {
	padding: 4px 10px;
	background-color: #21365c;
	color: #00cff6 !important;
	border: 1px solid #00d7ff;
	border-radius: 5px;
	z-index: 1;
	max-width: 200px;
}

/* label 为空的样式 */
.emptyFlowLabel {
}

.flow-endpoint-dot {
	background-color: #1879ff;
	border-radius: 10px;
	z-index: 2;
	border: 1px #eee solid;
	cursor: crosshair;
}

.flow-endpoint-dot-hover {
	background-color: #1524ff;
}

.ef-rectangle {
	background-color: #1879ff;
}

.ef-rectangle-hover {
	background-color: red;
}
.ef-drop-hover {
	border: 1px dashed #1879ff;
}
</style>
